# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.1078.1.14 -> 1.1078.1.15
#	       kernel/time.c	1.11    -> 1.12   
#	      kernel/timer.c	1.52    -> 1.53   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/05/14	davidm@tiger.hpl.hp.com	1.1078.1.15
# Change last_time_offset into last_nsec_offset and make it work for real.
# --------------------------------------------
#
diff -Nru a/kernel/time.c b/kernel/time.c
--- a/kernel/time.c	Thu May 15 13:41:55 2003
+++ b/kernel/time.c	Thu May 15 13:41:55 2003
@@ -35,7 +35,7 @@
  */
 struct timezone sys_tz;
 
-extern unsigned long last_time_offset;
+extern unsigned long last_nsec_offset;
 
 #if !defined(__alpha__) && !defined(__ia64__)
 
@@ -79,7 +79,7 @@
 	write_seqlock_irq(&xtime_lock);
 	xtime.tv_sec = value;
 	xtime.tv_nsec = 0;
-	last_time_offset = 0;
+	last_nsec_offset = 0;
 	time_adjust = 0;	/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_maxerror = NTP_PHASE_LIMIT;
@@ -125,7 +125,7 @@
 {
 	write_seqlock_irq(&xtime_lock);
 	xtime.tv_sec += sys_tz.tz_minuteswest * 60;
-	last_time_offset = 0;
+	last_nsec_offset = 0;
 	write_sequnlock_irq(&xtime_lock);
 }
 
@@ -381,7 +381,7 @@
 	txc->calcnt	   = pps_calcnt;
 	txc->errcnt	   = pps_errcnt;
 	txc->stbcnt	   = pps_stbcnt;
-	last_time_offset = 0;
+	last_nsec_offset = 0;
 	write_sequnlock_irq(&xtime_lock);
 	do_gettimeofday(&txc->time);
 	return(result);
diff -Nru a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c	Thu May 15 13:41:55 2003
+++ b/kernel/timer.c	Thu May 15 13:41:55 2003
@@ -451,6 +451,7 @@
  */
 struct timespec xtime __attribute__ ((aligned (16)));
 struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
+unsigned long last_nsec_offset;
 
 /* Don't completely fail for HZ > 500.  */
 int tickadj = 500/HZ ? : 1;		/* microsecs */
@@ -605,7 +606,7 @@
 /* in the NTP reference this is called "hardclock()" */
 static void update_wall_time_one_tick(void)
 {
-	long time_adjust_step;
+	long time_adjust_step, delta_nsec;
 
 	if ( (time_adjust_step = time_adjust) != 0 ) {
 	    /* We are doing an adjtime thing. 
@@ -621,11 +622,11 @@
 		time_adjust_step = tickadj;
 	     else if (time_adjust < -tickadj)
 		time_adjust_step = -tickadj;
-	     
+
 	    /* Reduce by this step the amount of time left  */
 	    time_adjust -= time_adjust_step;
 	}
-	xtime.tv_nsec += tick_nsec + time_adjust_step * 1000;
+	delta_nsec = tick_nsec + time_adjust_step * 1000;
 	/*
 	 * Advance the phase, once it gets to one microsecond, then
 	 * advance the tick more.
@@ -634,13 +635,33 @@
 	if (time_phase <= -FINEUSEC) {
 		long ltemp = -time_phase >> (SHIFT_SCALE - 10);
 		time_phase += ltemp << (SHIFT_SCALE - 10);
-		xtime.tv_nsec -= ltemp;
+		delta_nsec -= ltemp;
 	}
 	else if (time_phase >= FINEUSEC) {
 		long ltemp = time_phase >> (SHIFT_SCALE - 10);
 		time_phase -= ltemp << (SHIFT_SCALE - 10);
-		xtime.tv_nsec += ltemp;
+		delta_nsec += ltemp;
+	}
+	xtime.tv_nsec += delta_nsec;
+
+	/*
+	 * The whole point of last_nsec_offset is that it can be updated atomically and
+	 * lock-free.  Thus, arches that don't have __HAVE_ARCH_CMPXCHG probably can't use
+	 * last_nsec_offset anyhow... --davidm 2003-Feb-11
+	 */
+#ifdef __HAVE_ARCH_CMPXCHG
+	if (last_nsec_offset > 0) {
+		unsigned long new, old;
+
+		do {
+			old = last_nsec_offset;
+			if (old > delta_nsec)
+				new = old - delta_nsec;
+			else
+				new = 0;
+		} while (cmpxchg(&last_nsec_offset, old, new) != old);
 	}
+#endif
 }
 
 /*
@@ -777,7 +798,6 @@
 #ifndef ARCH_HAVE_XTIME_LOCK
 seqlock_t xtime_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED;
 #endif
-unsigned long last_time_offset;
 
 /*
  * This function runs timers and the timer-tq in bottom half context.
@@ -811,7 +831,6 @@
 		wall_jiffies += ticks;
 		update_wall_time(ticks);
 	}
-	last_time_offset = 0;
 	calc_load(ticks);
 }